package wsi.gui.resolve;

import javafx.application.Platform;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.scene.control.TreeItem;
import javafx.scene.input.MouseEvent;
import javafx.stage.WindowEvent;

import org.rygh.gui.comp.Label;
import org.rygh.gui.comp.Table;
import org.rygh.gui.comp.Tree;
import org.rygh.gui.model.Presenter;
import org.rygh.gui.model.callback.Callback;
import org.rygh.gui.window.Window;

import wsi.gui.resolve.model.FunctionFileTuple;
import wsi.gui.resolve.model.FunctionStatData;
import wsi.gui.resolve.model.FunctionStatTuple;
import wsi.gui.resolve.model.JudgeItem;
import wsi.gui.resolve.task.AutoJudgeTask;
import wsi.gui.resolve.task.ComputePrecisionTask;
import wsi.gui.resolve.task.PopulateServiceTask;
import wsi.gui.resolve.task.UpdateInformationTask;

public class ResolvePresenter extends Presenter {

	public interface Display extends Presenter.Display {

	}

	private JudgePresenter judgePresenter;
	private final FunctionFilePresenter filePresenter = new FunctionFilePresenter();

	private String service;

	public ResolvePresenter() {
		String title = "XML to RDF Match @ Instance Level";
		display = new Window(title, new ResolveView(this), 800, 600);

		bind();

		precision();
	}

	@Override
	public void bind() {
		getTree().setOnMouseClicked(new EventHandler<MouseEvent>() {
			@Override
			public void handle(MouseEvent event) {
				TreeItem<String> item = getTree().getSelectionModel()
						.getSelectedItem();

				if (item == null || !item.isLeaf())
					return;

				service = item.getValue();
				populate();
			};
		});

		getTable().setOnMouseClicked(new EventHandler<MouseEvent>() {

			@Override
			public void handle(MouseEvent event) {
				if (event.getClickCount() != 2)
					return;

				FunctionStatTuple item = getTable().getSelectionModel()
						.getSelectedItem();

				if (item == null)
					return;

				review(item);
			}
		});

		getWindow().bindCloseToPresenter();

		filePresenter.setCallback(new Callback<FunctionFileTuple>() {

			@Override
			public void call(FunctionFileTuple value) {
				judge(value);
			}
		});

		filePresenter.getWindow().setOnCloseRequest(
				new EventHandler<WindowEvent>() {

					@Override
					public void handle(WindowEvent event) {
						updateInformation();
						populate();
					}
				});
	}

	@Override
	public void close() {
		super.close();
		Platform.exit();
	}

	private Label getDownLabel() {
		return invoke("display.view.topView.downLabel");
	}

	private Table<FunctionStatTuple> getTable() {
		return invoke("display.view.tableView.table");
	}

	private Tree<String> getTree() {
		return invoke("display.view.treeView.tree");
	}

	private Label getUpLabel() {
		return invoke("display.view.topView.upLabel");
	}

	private void initJudgPresenter() {
		if (judgePresenter != null)
			return;

		judgePresenter = new JudgePresenter();

		judgePresenter.getWindow().setOnCloseRequest(
				new EventHandler<WindowEvent>() {

					@Override
					public void handle(WindowEvent event) {
						updateInformation();
						populate();

						filePresenter.refresh();
					}
				});

	}

	public void judge() {
		initJudgPresenter();

		judgePresenter.judgeAll();
		judgePresenter.display();
	}

	private void judge(FunctionFileTuple tuple) {
		initJudgPresenter();

		JudgeItem item = new JudgeItem(tuple.getFunction(), tuple.getXmlFile(),
				tuple.getJudgeFile());
		assert item.isValid();

		judgePresenter.judge(item);
		judgePresenter.display();
	}

	public void judgeAuto() {
		AutoJudgeTask task = new AutoJudgeTask();

		getUpLabel().textProperty().bind(task.messageProperty());

		task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

			@Override
			public void handle(WorkerStateEvent event) {
				precision();
			}
		});

		Thread t = new Thread(task);
		t.setDaemon(true);
		t.start();

	}

	private void populate() {
		final PopulateServiceTask task = new PopulateServiceTask(service);

		getTable().clear();

		task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

			@Override
			public void handle(WorkerStateEvent event) {
				FunctionStatData data = task.getValue();
				getTable().setData(data);
			}
		});

		Thread t = new Thread(task);
		t.setDaemon(true);
		t.start();
	}

	public void precision() {
		updateInformation();

		ComputePrecisionTask task = new ComputePrecisionTask();

		getDownLabel().textProperty().bind(task.messageProperty());

		Thread t = new Thread(task);
		t.setDaemon(true);
		t.start();
	}

	private void review(FunctionStatTuple item) {
		filePresenter.setItem(item);
		filePresenter.refresh();
		filePresenter.display();
	}

	private void updateInformation() {
		UpdateInformationTask task = new UpdateInformationTask();

		getUpLabel().textProperty().bind(task.messageProperty());

		Thread t = new Thread(task);
		t.setDaemon(true);
		t.start();
	}
}
